package com.simple.mqtt.common.task;

import com.simple.mqtt.common.tool.LogTool;

import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * MQTT message acknowledgment task for QoS1/QoS2 level message retry mechanism
 */
public class AckTimerTask implements Runnable {
    // Task to execute
    private final Runnable command;
    // Maximum retry count
    private final int maxRetryCount;
    // Retry interval (milliseconds)
    private final long delayMillis;
    // Scheduled executor
    private final ScheduledExecutorService scheduler;
    // Current retry count
    private int count = 0;
    // For canceling task
    private ScheduledFuture<?> scheduledFuture;

    /**
     * Construct acknowledgment task
     *
     * @param scheduler         ScheduledExecutorService instance
     * @param command           task to execute
     * @param maxRetryCount     maximum retry count
     * @param retryIntervalSecs retry interval (seconds)
     */
    public AckTimerTask(ScheduledExecutorService scheduler,
                        Runnable command,
                        int maxRetryCount,
                        int retryIntervalSecs) {
        this.scheduler = Objects.requireNonNull(scheduler, "Scheduler cannot be null");
        this.command = Objects.requireNonNull(command, "Task command cannot be null");
        this.maxRetryCount = maxRetryCount;
        this.delayMillis = TimeUnit.SECONDS.toMillis(retryIntervalSecs);
    }

    @Override
    public void run() {
        try {
            command.run(); // Execute task
            LogTool.debug("MQTT acknowledgment task executed successfully");
        } catch (Exception e) {
            LogTool.error("MQTT acknowledgment task execution exception", e);

            count++; // Increment retry count

            // If maximum retry count not reached, schedule next retry
            if (count <= maxRetryCount) {
                scheduledFuture = scheduler.schedule(this, delayMillis, TimeUnit.MILLISECONDS);
                LogTool.info("MQTT acknowledgment task retry {} scheduled, executing after {} milliseconds", count, delayMillis);
            } else {
                LogTool.warn("MQTT acknowledgment task reached maximum retry count ({}), stopping retry", maxRetryCount);
            }
        }
    }

    /**
     * Start task scheduling
     */
    public void start() {
        scheduledFuture = scheduler.schedule(this, delayMillis, TimeUnit.MILLISECONDS);
        LogTool.info("MQTT acknowledgment task started, first execution after {} milliseconds", delayMillis);
    }

    /**
     * Cancel task
     */
    public void cancel() {
        if (scheduledFuture != null && !scheduledFuture.isDone()) {
            scheduledFuture.cancel(false);
            LogTool.info("MQTT acknowledgment task canceled");
        }
    }
}